﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;

namespace Simple.Common.Core.Attributes
{
    /// <summary>
    /// 安全签名
    /// </summary>
    public class SignatureHelper
    {
        /// <summary>
        /// Gets or sets the error MSG.
        /// </summary>
        /// <value>The error MSG.</value>
        public string ErrMsg { get; set; }

        /*
         * 签名逻辑：
         * 1、签名参数：将所有的参数以升序的方式排序（不区分get和post），最后附加access_token的expires_in参数，进行签名
         * 2、签名密钥：项目名称
         */

        /// <summary>
        /// 检查提交的参数签名
        /// </summary>
        /// <param name="getCollection">要验证的QueryCollection</param>
        /// <param name="maxSecond">超时时间，单位：秒</param>
        /// <param name="signKey">签名</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public bool CheckSignature(IQueryCollection getCollection, string signKey,string signature,string timestamp,int maxSecond=600)
        {
            IDictionary<string, string> parameters = new Dictionary<string, string>();
            foreach (string key in getCollection.Keys)
            {
                //不包括的参数
                if (key.ToUpper() == "access_token".ToUpper())
                {
                    continue;
                }
                else
                {
                    parameters.Add(key, getCollection[key].ToString());
                }
            }
            if (string.IsNullOrEmpty(signature))
            {
                this.ErrMsg = "未找到签名";
                return false;
            }
            else
            {
                //时间校验
                DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
                long lTime = long.Parse(timestamp + "0000000");
                TimeSpan toNow = new TimeSpan(lTime);
                DateTime dtResult = dtStart.Add(toNow);

                if ((DateTime.Now - dtResult).TotalSeconds > maxSecond)
                {
                    this.ErrMsg = "签名已过期";
                    return false;
                }
                var result=GetSignature(parameters, signKey,timestamp);
                return signature == result;
            }
        }

        /// <summary>
        /// 检查POST提交的参数签名
        /// </summary>
        /// <param name="formCollection"></param>
        /// <param name="signKey"></param>
        /// <param name="maxSecond"></param>
        /// <returns></returns>
        public bool CheckSignature(IDictionary<string,object> data, string signKey, int maxSecond=600)
        {
            string Signature = "", timestamp = "";
            IDictionary<string, string> parameters = new Dictionary<string, string>();
            foreach (string key in data.Keys)
            {
                var type = data[key].GetType();
                //不包括的参数
                if (key.ToUpper() == "access_token".ToUpper())
                    continue;
                //timestamp
                else if (key.ToUpper() == "timestamp".ToUpper())
                    timestamp = data[key].ToString();
                //SIGNKEY
                else if (key.ToUpper() == "signature".ToUpper())
                    Signature = data[key].ToString();
                else {
                    if (type == typeof(string))
                        parameters.Add(key, data[key].ToString());
                    else
                        parameters.Add(key, JsonConvert.SerializeObject(data[key]));
                }
            }
            if (string.IsNullOrEmpty(Signature))
            {
                this.ErrMsg = "未找到签名";
                return false;
            }
            else
            {
                //时间校验
                DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
                long lTime = long.Parse(timestamp + "0000000");
                TimeSpan toNow = new TimeSpan(lTime);
                DateTime dtResult = dtStart.Add(toNow);

                if ((DateTime.Now - dtResult).TotalSeconds > maxSecond)
                {
                    this.ErrMsg = "签名已过期";
                    return false;
                }
                var result=GetSignature(parameters, signKey,timestamp);
                return Signature == result;
            }
        }
        /// <summary>
        /// 计算参数签名
        /// </summary>
        /// <param name="parameters">请求参数集，所有参数必须已转换为字符串类型</param>
        /// <param name="signKey">签名密钥</param>
        /// <returns>签名</returns>
        private string GetSignature(IDictionary<string, string> parameters, string signKey,string timestamp)
        {
            // 先将参数以其参数名的字典序升序进行排序
            IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
            IEnumerator<KeyValuePair<string, string>> iterator = sortedParams.GetEnumerator();

            // 遍历排序后的字典，将所有参数按"key=value"格式拼接在一起
            StringBuilder basestring = new StringBuilder();
            while (iterator.MoveNext())
            {
                string key = iterator.Current.Key;
                string value = iterator.Current.Value;
                if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
                {
                    basestring.Append(key).Append("=").Append(value);
                }
            }
            basestring.Append($"timestamp={timestamp}");
            basestring.Append(",").Append(signKey);

            System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();
            byte[] buffer = md5.ComputeHash(Encoding.UTF8.GetBytes(basestring.ToString()));
            return System.BitConverter.ToString(buffer).Replace("-", "").ToUpper();
        }
    }
}
